<template>
    <!-- <div>
        新增/编辑SPU - SpuForm
        <el-button @click="emit('update:modelValue', STATUS.SPULIST)">取消</el-button>
    </div> -->

    <el-form label-width="100px">
        <el-form-item label="SPU名称">
            <el-input v-model="spuForm.spuName" placeholder="SPU名称"></el-input>
        </el-form-item>

        <el-form-item label="品牌">
            <el-select v-model="spuForm.tmId" placeholder="请选择">
                <el-option v-for="tm in tmList" :key="tm.id" :label="tm.tmName" :value="tm.id!">
                </el-option>
            </el-select>
        </el-form-item>

        <el-form-item label="SPU描述">
            <el-input v-model="spuForm.description" type="textarea" :rows="3" placeholder="SPU描述" />
        </el-form-item>

        <el-form-item label="SPU图片">
            <el-upload v-model:file-list="(spuImageList as any)" :action="uploadAction" list-type="picture-card"
                :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handlerSuccess">
                <el-icon>
                    <Plus />
                </el-icon>
            </el-upload>
            <el-dialog v-model="dialogVisible">
                <img w-full :src="dialogImageUrl" alt="Preview Image" />
            </el-dialog>
        </el-form-item>

        <el-form-item label="销售属性">
            <div class="mb-10">
                <el-select v-model="saleIdName" class="mr-10" :placeholder="`还有${saleAttrList.length}个未选择`">
                    <el-option v-for="saleAttr in saleAttrList" :key="saleAttr.id" :label="saleAttr.name"
                        :value="`${saleAttr.id}:${saleAttr.name}`"></el-option>
                </el-select>
                <el-button type="primary" @click="addSaleAttr">添加销售属性</el-button>
            </div>
            <el-table :data="spuForm.spuSaleAttrList" border size="small">
                <el-table-column type="index" label="序号" width="80" align="center" />
                <el-table-column type="属性名" prop="saleAttrName" width="200" />
                <el-table-column label="属性值列表">
                    <template #default="{ row, $index }">
                        <el-tag v-for="(tag, index) in row.spuSaleAttrValueList" :key="tag" class="mr-5" closable
                            :disable-transitions="false" @close="handleClose(index, row.spuSaleAttrValueList)">
                            {{ tag.saleAttrValueName }}
                        </el-tag>
                        <!-- 默认是没有 row.inputVisible 这个值,是undefined,此时展示button
                        当点击button按钮的时候,此时给 row.inputVisible 设置为 true,那么此时就展示成了input
                        当input失焦或者点击回车的时候,此时将 row.inputVisible 设置为 false,呢么此时展示成button -->
                        <el-input v-if="row.inputVisible" ref="InputRef" v-model="row.inputValue" size="small"
                            style="width:100px" @keyup.enter="handleInputConfirm(row)"
                            @blur="handleInputConfirm(row)" />
                        <el-button v-else size="small" @click="showInput(row)">新增</el-button>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="80">
                    <template #default="{ row, $index }">
                        <el-button type="danger" size="small" :icon="Delete"
                            @click="deleteSaleAttr($index)"></el-button>
                    </template>
                </el-table-column>
            </el-table>
        </el-form-item>

        <el-form-item>
            <el-button type="primary" @click="onSave">保存</el-button>
            <el-button @click="cancelSave">取消</el-button>
        </el-form-item>
    </el-form>

</template>
  
<script setup lang="ts">
import { ElMessage, type UploadProps, type UploadUserFile, type UploadFile, type UploadFiles } from 'element-plus'
import { STATUS } from '../../index.vue'
import { Delete, Plus } from '@element-plus/icons-vue'
import { onMounted, ref, nextTick, computed } from 'vue'
import trademarkApi, { type TrademarkModel } from '@/api/trademark'
// 这里飘红的原因: 因为这个类型引入的不对,我们什么时候会使用这种引入方式,当spuApi和 类型一起引入,同时在js中使用就不会飘红
// import type { SaleAttrModel } from '@/api/spu' // 单独引入类型需要将type 放到花括号外面
import spuApi, { type SaleAttrModel, type SpuModel, type SpuImageModel, type SpuSaleAttrValueModel, type SpuSaleAttrModel } from '@/api/spu' // 当类型和spuApi同时引入的时候,type需要放到花括号里面
import useCategoryStore from '@/stores/category'
import { cloneDeep } from 'lodash';


const categoryStore = useCategoryStore()// 得到categoryStore

const uploadAction = `${import.meta.env.VITE_API_URL}/admin/product/upload`

const props = defineProps<{
    modelValue: number,
    spuInfo: SpuModel
}>()

const emit = defineEmits<{
    (e: 'update:modelValue', status: number): void,
    (e: 'changeSpuInfo'): void
}>()


const onSave = async () => {
    // 组装数据 - 组装保存的时候需要的数据
    spuForm.value.category3Id = categoryStore.category3Id!;
    // spuName、descriptiontmId、tmId 使用 v-model 收集
    // 图片数据组装
    // 图片数据使用的是 uploadFiles,这里面放的都是 uploadFile,而uploadFile中有 url 和 name 和 response
    // 其中 url 是本地数据,和我们上传要求的数据格式不一样,需要组装数据
    // imgName
    // imgUrl
    let spuImageListTemp = spuImageList.value.map(item => {
        return {
            imgName: item.name,
            imgUrl: item.imgUrl || item.response.datam,
        }
    })
    spuForm.value.spuImageList = spuImageListTemp as any;
    // 把销售属性的 inputVisible 和 inputValue 删除掉(不删也可以,但是接口中就会带着个数据了,带上这俩数据不影响后端,影响自己看数据)
    spuForm.value.spuSaleAttrList.forEach(row => {
        delete row.inputValue
        delete row.inputVisible
    })
    // 做个简单校验
    let { category3Id, spuName, tmId, description, spuImageList: sIList, spuSaleAttrList } = spuForm.value;
    if (!(category3Id && spuName && tmId && description && sIList.length && spuSaleAttrList.length)) {
        ElMessage.error('SPU名称、品牌、三级分类、描述、图片列表、销售属性数据可能为空,请检查输入')
        return
    }
    try {
        if (spuForm.value.id) {
            await spuApi.updataSpu(spuForm.value)
        } else {
            await spuApi.saveSpu(spuForm.value);
        }
        ElMessage.success(' 保存成功')
        cancelSave();// 切换驻列表
        // 刷新列表需要在 SpuList 组件中的 watch 监听 加 immediate
    } catch (error) {
        ElMessage.error('保存失败，请重试')
    }
}


const cancelSave = () => {
    emit('update:modelValue', STATUS.SPULIST); //  切换页面
    emit('changeSpuInfo')
}




// 收集销售属性
const saleIdName = ref<string>('')
// 添加销售属性到列表
const addSaleAttr = () => {
    if (!saleIdName.value) {
        return
    }
    let [id, name] = saleIdName.value.split(':');// 解构出来id和name
    // 给表格添加数据
    spuForm.value.spuSaleAttrList.push({
        baseSaleAttrId: Number(id),
        saleAttrName: name,
        spuSaleAttrValueList: []
    })
    // 重置收集下拉数据的变量
    saleIdName.value = ''
}

const saleAttrList = computed(() => {
    if (!spuForm.value.spuSaleAttrList) {
        return []
    }
    let tableSaleIdArr = spuForm.value.spuSaleAttrList.map(item => item.baseSaleAttrId)
    return baseSaleAttrList.value.filter(item => !tableSaleIdArr.includes(item.id))
})

// 删除属性值
const handleClose = (index: number, spuSaleAttrValueList: SpuSaleAttrValueModel[]) => {
    spuSaleAttrValueList.splice(index, 1)
}

const InputRef = ref<HTMLInputElement>()

// input框回车确认的回调，需要把input切换成div展示
const handleInputConfirm = (row: SpuSaleAttrModel) => {
    row.inputVisible = false;
    // 校验空值，如果为空，直接return，不添加到销售属性值列表
    if (!row.inputValue?.trim()) {
        return
    }
    // 重复校验
    if (row.spuSaleAttrValueList.map(item => item.saleAttrValueName).includes(row.inputValue)) {
        ElMessage.error('输入的属性值重复，请重新输入')
        row.inputValue = ""// 清空刚才输入的值
        return
    }
    // 当失焦或者点击回车的时候,此时需要获取到input框输入的值,添加到前面循环的tag中
    // 而 tag 循环的数据是"销售属性值"列表,也就是 row.spuSaleAttrValueList
    row.spuSaleAttrValueList.push({
        baseSaleAttrId: row.baseSaleAttrId,// 销售属性值的id就 是 销售属性的id
        saleAttrValueName: row.inputValue!,// row.inputValue 是input的v-model绑定的值,输入的值
    })
    // 当讲输入的数据添加完成的时候,此时需要把 row.inputValue 清空
    row.inputValue = ""
}
// 点击“新增”按钮的回调，需要把div切换成input展示
const showInput = (row: SpuSaleAttrModel) => {
    row.inputVisible = true;// 切换input展示
    // 等待DOM更新完毕之后，获取到input实例，进行聚焦
    nextTick(() => {
        InputRef.value?.focus()
    })
}

// 删除销售属性列
const deleteSaleAttr = (index: number) => {
    spuForm.value.spuSaleAttrList.splice(index, 1)
}






// 图片上传相关数据和回调
const spuImageList = ref<SpuImageModel[]>([])// 单独收集图片的数据
const dialogImageUrl = ref('') // 预览图片的url
const dialogVisible = ref(false) // 预览图片展示dialog
// 上传成功的回调
const handlerSuccess: UploadProps['onSuccess'] = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
    // console.log('uploadFiles -> ', uploadFiles)
    // response - 接口返回来的数据
    // uploadFile - 当前上传图片的信息,对象中有很多属性
    //    name 图片的名称
    //    url  图片本地的一个地址 - 注意: 这个地址不是我们收集的地址,是本地的,仅用于预览
    //    response  这个response就是参数一response
    // uploadFiles
    //    是一个数组,数组中放的都是 参数二uploadFile,数组是当前所有的图片组成的图片列表

    // 其他地方不用管,直接把参数三当前的图片列表赋值给我们收集数据的变量,此时飘红
    // 等号左右两边的类型不同的时候,将等号右侧数据的类型 断言成一个 any,就可以让TS通过类型了 - 这里可以理解为让TS强行通过类型
    spuImageList.value = uploadFiles as any
}
// 删除图片的回调
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
    // console.log(uploadFile, uploadFiles)
    spuImageList.value = uploadFiles as any
}
// 预览图片的回调
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
    dialogImageUrl.value = uploadFile.url!
    dialogVisible.value = true
}
// 当前页面必须有 category3Id 才能打开,【后续】要给主列表界面的"添加SPU"按钮加限制条件
const initSpuForm = (): SpuModel => ({
    spuName: '',
    description: '',
    category3Id: categoryStore.category3Id as number,
    tmId: undefined,
    spuSaleAttrList: [],
    spuImageList: [],
})
// spuForm收集页面数据
const spuForm = ref<SpuModel>(initSpuForm())

// 产品下拉数据
const tmList = ref<TrademarkModel[]>([])
const getTrademarkData = async () => {
    try {
        let result = await trademarkApi.getTrademarkList()
        tmList.value = result
    } catch (error) {
        ElMessage.error('获取品牌下拉数据失败，请重试')
    }
}

// 销售属性下拉数据
const baseSaleAttrList = ref<SaleAttrModel[]>([])
const getSaleAttrData = async () => {
    try {
        let result = await spuApi.getSaleAttrList();
        baseSaleAttrList.value = result
    } catch (error) {
        ElMessage.error('获取销售属性下拉失败，请重试')

    }
}

// 编辑回显根据spuId获取图片列表
const getSpuImageListBySpuId = async () => {
    try {
        let result = await spuApi.getSpuImageLIstBySpuId(props.spuInfo.id!)
        // 图片列表的数据是用了一个单独数据收集的,回显的时候也需要用这个单独的数据
        spuImageList.value = result.map(item => {
            return {
                ...item,
                name: item.imgName,// upload组件展示必须要有name和url属性
                url: item.imgUrl
            }
        })
    } catch (error) {
        ElMessage.error('获取图片列表失败,请重试')
    }
}
// 编辑回显根据spuId获取销售属性列表
const getSaleAttrListBySpuId = async () => {
    try {
        let result = await spuApi.getSpuSaleAttrListBySpuId(props.spuInfo.id!)
        spuForm.value.spuSaleAttrList = result
    } catch (error) {
        ElMessage.error('获取销售属性列表失败,请重试')
    }
}

const initData = () => {
    getTrademarkData();
    getSaleAttrData();
    if (props.spuInfo.id) { // 编辑的时候是有id的
        spuForm.value = cloneDeep(props.spuInfo); // 回显数据
        // 图片列表和销售属性需要发请求拿回来
        getSpuImageListBySpuId();
        getSaleAttrListBySpuId();
    }
}
onMounted(() => {
    initData()
})
</script>
  
<style scoped>

</style>